package com.pwr.app.classification;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import com.pwr.app.Pattern;

public class NearestNeighbour implements BaseClassification {

	ArrayList<Pattern> patterns;
	private int nearestNeighborCount = 3;

	private class Neighbor {
		double difference = 0;
		int letter = 0;
		int count = 0;
	}

	public static class NeighborComparable implements Comparator<Neighbor> {
		@Override
		public int compare(Neighbor o1, Neighbor o2) {
			return o1.difference > o2.difference ? 1 : o1.difference == o2.difference ? 0 : -1;
		}
	}

	public static class NeighborCountComparable implements Comparator<Neighbor> {
		@Override
		public int compare(Neighbor o1, Neighbor o2) {
			return o1.count > o2.count ? 1 : o1.count == o2.count ? 0 : -1;
		}
	}

	@Override
	public int present(double[] pattern) {
		List<Neighbor> closestNeighborList = new ArrayList<Neighbor>();
		for (int i = 0; i < patterns.size(); i++) {
			double[] tempPat = patterns.get(i).getPattern();
			double tempDifference = 0;

			for (int l = 0; l < tempPat.length; l++) {
				tempDifference = tempDifference + Math.pow(tempPat[l] - pattern[l], 2);
			}
			tempDifference = Math.sqrt(tempDifference);
			if (closestNeighborList.size() < nearestNeighborCount) {
				Neighbor temp = new Neighbor();
				temp.difference = tempDifference;
				temp.letter = patterns.get(i).getLetter();
				closestNeighborList.add(temp);
				Collections.sort(closestNeighborList, new NeighborComparable());
			} else {
				for (int l = 0; l < closestNeighborList.size(); l++) {
					if (closestNeighborList.get(l).difference > tempDifference) {
						closestNeighborList.remove(l);
						Neighbor temp = new Neighbor();
						temp.difference = tempDifference;
						temp.letter = patterns.get(i).getLetter();
						closestNeighborList.add(temp);
						Collections.sort(closestNeighborList, new NeighborComparable());
						break;
					}
				}
			}

		}
		List<Neighbor> mostOftenNeighbour = new ArrayList<Neighbor>();
		for (int i = 0; i < closestNeighborList.size(); i++) {
			if (mostOftenNeighbour.size() == 0) {
				mostOftenNeighbour.add(closestNeighborList.get(i));
				mostOftenNeighbour.get(0).count = 1;
			} else {
				for (int l = 0; l < mostOftenNeighbour.size(); l++) {
					if (mostOftenNeighbour.get(l).letter == closestNeighborList.get(i).letter) {
						mostOftenNeighbour.get(l).count++;
					} else {
						mostOftenNeighbour.add(closestNeighborList.get(i));
						mostOftenNeighbour.get(0).count = 1;
					}
				}
			}
		}
		Collections.sort(closestNeighborList, new NeighborCountComparable());
		return closestNeighborList.get(0).letter;
	}

	@Override
	public void teach(ArrayList<Pattern> patterns) {
		this.patterns = patterns;
	}

	public int getNearestNeighborCount() {
		return nearestNeighborCount;
	}

	public void setNearestNeighborCount(int nearestNeighborCount) {
		this.nearestNeighborCount = nearestNeighborCount;
	}

}
